﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SaunaClient.Model.Logger;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Net.Sockets;
using SaunaClient.Model.Network;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace SaunaClient.Controller.Communication
{
    /// <summary>
    /// Communication Manager Class
    /// </summary>
    /// <dates>
    /// 29/09/2011 - created by Chiaki Sato
    /// </dates>
    /// <remarks>
    /// Note:
    /// This class is thread safe. 
    /// </remarks>
    public class CommunicationManager : ICommunicationManager
    {
        private ITcpFactory tcpFactory;
        private IFtpFactory ftpFactory;
        private IFtpDaoGateway ftps;
        private ITcpDaoGateway tcp;
        private NetworkSetting networkSetting;
        private const string FTP_SSL = "FtpSsl";
        private const string TCP_SSL = "TcpSsl";
        private const string CONFIG_FILE_NAME = @"SaunaConfig.ini";
        private bool isConnectedToServer = false;
        private string currentLoginUserId = "anonymous";

        // Public Enumeration
        public enum LoginResult { SUCCESS = 1, USER_REJECTED = 2, PROTOCOL_ERROR = 3 }

        /// <summary>
        /// Public Constructor
        /// </summary>
        public CommunicationManager()
        {
            // Read Sauna configuration file and create network setting 
            networkSetting = ReadConfigFile();
            if (networkSetting == null)
            {
                // When Sauna configuration file does not exist, create network setting with default values
                networkSetting = new NetworkSetting();
            }

            // Make tcp communication handler
            tcpFactory = new TcpFactoryImplementation();
            tcp = tcpFactory.Make(TCP_SSL, networkSetting);
            isConnectedToServer = tcp.IsConnectedToServer();

            // Make ftp communication handler
            ftpFactory = new FtpFactoryImplementation();
            ftps = ftpFactory.Make(FTP_SSL, networkSetting);
        }

        /// <summary>
        /// Request user account authentication to server
        /// </summary>
        /// <param name="userId">User ID</param>
        /// <param name="password">Password</param>
        /// <returns>Authentication Status</returns>
        public UserAuthenticationStatus AuthenticationRequest(string userId, string password)
        {

            TcpTransferStatus tcpTransferStatus = tcp.SendLoginRequestToServer(userId, password);
            if (tcpTransferStatus.GetStatus() == TcpTransferStatus.Status.SUCCESS)
            {
                currentLoginUserId = userId;
                return (new UserAuthenticationStatus(UserAuthenticationStatus.Status.SUCCESS));
            }
            else if (tcpTransferStatus.GetStatus() == TcpTransferStatus.Status.USER_REJECTED)
            {
                return (new UserAuthenticationStatus(UserAuthenticationStatus.Status.USER_REJECTED));
            }
            else if (tcpTransferStatus.GetStatus() == TcpTransferStatus.Status.CONNECT_ERROR)
            {
                return (new UserAuthenticationStatus(UserAuthenticationStatus.Status.CONNECT_ERROR));
            }
            else
            {
                return (new UserAuthenticationStatus(UserAuthenticationStatus.Status.PROTOCOL_ERROR));
            }
        }

        /// <summary>
        /// Upload a file
        /// </summary>
        /// <param name="localDirectory">Local directory</param>
        /// <param name="localFileName">File name</param>
        public void Upload(string localDirectory, string localFileName, string serverDirectory)
        {
            ftps.Upload(localDirectory, localFileName, serverDirectory);
        }

        /// <summary>
        /// Download a file
        /// </summary>
        /// <param name="serverDirectory">Server directory</param>
        /// <param name="serverFileName">Server file name</param>
        /// <param name="localDirectory">Local directory</param>
        public void Download(string serverDirectory, string serverFileName, string localDirectory)
        {
            // Begin Two Phaise Transaction
            ftps.Download(serverDirectory, serverFileName, localDirectory);
            tcp.SendDownloadLogToServer(currentLoginUserId, serverFileName, DateTime.Now);
            // End Two Phaise Transaction
        }

        /// <summary>
        /// Get Server File List
        /// </summary>
        /// <param name="serverDirectory">Server directory</param>
        public String GetServerFileList(string serverDirectory)
        {
            String fileList = ftps.GetServerFileList(serverDirectory);
            return fileList;
        }

        /// <summary>
        /// Read network setting from config file
        /// </summary>
        /// <returns>NetworkSetting</returns>
        public NetworkSetting ReadConfigFile()
        {
            NetworkSetting objNetworkSetting = null;
            try
            {
                using (Stream stream = new FileStream(CONFIG_FILE_NAME, FileMode.Open, FileAccess.Read))
                {
                    IFormatter formatter = new BinaryFormatter();
                    objNetworkSetting = (NetworkSetting)formatter.Deserialize(stream);
                }
            }
            catch (FileNotFoundException ex)
            {
                // Write error.
                Console.WriteLine(ex);
            }
            return objNetworkSetting;
        }

        /// <summary>
        /// Check if client is connected server
        /// </summary>
        /// <returns>Connection Status</returns>
        public bool IsConnectedToServer()
        {
            return isConnectedToServer;
        }

        /// <summary>
        /// Get FTP Server Directory path stting
        /// </summary>
        /// <returns>FTP Server Directory path</returns>
        public string GetFtpServerDirectory()
        {
            return networkSetting.FtpServerDirectory;
        }

        /// <summary>
        /// Get FTP Local Directory path setting
        /// </summary>
        /// <returns>FTP Local Directory path</returns>
        public string GetFtpLocalDirectory()
        {
            return networkSetting.FtpLocalDirectory;
        }

    }
}
